
# include "dfxWindow_Win32.h"
# include "dfxFile_Win32.h"
# include "dfxKeyboard_Win32.h"
# include "dfxThread_Win32.h"
# include "dfxMutex_Win32.h"
# include "dfxTimer_Win32.h"
# include "dfxLog.h"

# if defined DFX_DEBUG
    # pragma comment(lib, "../Debug/DFXEngine.lib")
# else
    # pragma comment(lib, "../Release/DFXEngine.lib")
# endif

namespace DFX
{
    extern "C"
    {
        DFXRESULT DFX_EXPORT_ONLY WindowCreate(const String &name, const String &className, Window **window);
        DFXRESULT DFX_EXPORT_ONLY RegisterWindowClass(const String &name);
        DFXRESULT DFX_EXPORT_ONLY UnregisterWindowClass(const String &name);

        DFXRESULT DFX_EXPORT_ONLY ProcessEvents();

        DFXRESULT DFX_EXPORT_ONLY FileCreate(const String &fileName, File **file);
        DFXRESULT DFX_EXPORT_ONLY ThreadCreate(PRIORITY priority, Thread **t);
        DFXRESULT DFX_EXPORT_ONLY MutexCreate(Mutex **m);
        DFXRESULT DFX_EXPORT_ONLY TimerCreate(Timer **t);
    }

    BOOL WINAPI DllEntryPoint(HINSTANCE hDll, DWORD dwReason, LPVOID lpvReserved)
    {
        switch (dwReason)
        {
        case DLL_PROCESS_ATTACH:
            break;

        case DLL_PROCESS_DETACH:
            break;

        default:
            break;
        }

        return TRUE;
    }

    DFXRESULT WindowCreate(const String &name, const String &className, Window **window)
    {
        if (!*window)
        {
            *window = new Window_Win32(name, className);
            return DFX_SUCCESS;
        }

        return DFX_CREATEWIN;
    }

    DFXRESULT RegisterWindowClass(const String &name)
    {
        static HINSTANCE instance = NULL;

        if (!instance)
            instance = GetModuleHandle(NULL);

        WNDCLASSEX wndClass;

        wndClass.cbSize = sizeof(WNDCLASSEX);
        wndClass.style = CS_HREDRAW | CS_VREDRAW;
        wndClass.lpfnWndProc = WindowProc;
        wndClass.cbClsExtra = 0;
        wndClass.cbWndExtra = 0;
        wndClass.hInstance = instance;
        wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
        wndClass.hbrBackground = NULL;
        wndClass.lpszMenuName = NULL;
        wndClass.lpszClassName = name.c_str();
        wndClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);

        if (!RegisterClassEx(&wndClass))
        {
            DFX_ERROR( "Unable to register class: %s", name.c_str());
            return DFX_REGCLASS;
        }

        return DFX_SUCCESS;
    }

    DFXRESULT UnregisterWindowClass(const String &name)
    {
        static HINSTANCE instance = NULL;

        if (!instance)
            instance = GetModuleHandle(NULL);

        if (!UnregisterClass(name.c_str(), instance))
        {
            DFX_ERROR( "Unable to unregister class: %s", name.c_str());
            return DFX_REGCLASS;
        }

        return DFX_SUCCESS;
    }

    DFXRESULT ProcessEvents()
    {
        MSG msg;

        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT)
            {
                return DFX_QUITMSG;
            }
            else
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }

        return DFX_SUCCESS;
    }

    DFXRESULT FileCreate(const String &fileName, File **file)
    {
        if (!*file)
        {
            *file = new File_Win32();
            
            DFXRESULT dr = (*file)->Open(fileName);

            if (DFX_FAILED(dr))
                SAFE_DELETE(*file);

            return dr;
        }

        return DFX_ERROR0;
    }

    DFXRESULT ThreadCreate(PRIORITY priority, Thread **t)
    {
        if (!*t)
        {
            *t = new Thread_Win32(priority);
            return DFX_SUCCESS;
        }

        return DFX_CREATEFAILED;
    }

    DFXRESULT MutexCreate(Mutex **m)
    {
        if (!*m)
        {
            *m = new Mutex_Win32(); 
            return DFX_SUCCESS;
        }

        return DFX_CREATEFAILED;
    }

    DFXRESULT TimerCreate(Timer **t)
    {
        if (!*t)
        {
            *t = new Timer_Win32();
            return DFX_SUCCESS;
        }

        return DFX_CREATEFAILED;
    }
}
